package cn.hfjava.kz.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hfjava.kz.common.listener.StudentDataListener;
import cn.hfjava.kz.entity.dto.StudentFormDTO;
import cn.hfjava.kz.entity.dto.StudentQueryDTO;
import cn.hfjava.kz.entity.excel.StudentExcel;
import cn.hfjava.kz.entity.po.Student;
import cn.hfjava.kz.entity.vo.PageVO;
import cn.hfjava.kz.exception.BizException;
import cn.hfjava.kz.mapper.StudentMapper;
import cn.hfjava.kz.service.StudentService;
import cn.hfjava.kz.validator.group.CreateGroup;
import cn.hfjava.kz.validator.group.UpdateGroup;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/v1/student")
@Slf4j
@Tag(name = "考生管理模块")
public class StudentController {

    // 自动注入/自动装配  (当一个bean需要使用到另一个bean时，自动创建另一个bean并注入到当前bean中)
    // byTye/byName/byConstructor
    // @Autowired/@Resource/ @Qualifier /@Inject
    @Resource
    private StudentService studentService;  // 注入我要依赖的业务组件(bean)


    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    //1、按多条件任意组合分页查询学生基本信息列表(查询条件：姓名、身份证号、手机号、申报状态<待审报、已审报>)

    //@CrossOrigin(origins = "http://localhost:9721")

    @Operation(summary = "分页查询考生",description = "根据条件分页查询考生信息")
    @PostMapping("/search")
    public SaResult searchPage(@RequestBody StudentQueryDTO studentQueryDTO){
        //1.设置分页信息
        IPage<Student> page = new Page<>(studentQueryDTO.getCurPage(),
                studentQueryDTO.getPageSize());
        //2.设置查询条件
        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
        //考生姓名
       queryWrapper.lambda().like(StringUtils.isNotBlank(
               studentQueryDTO.getName()),
               Student::getName,
               studentQueryDTO.getName());

        //手机号
        queryWrapper.lambda().like(StringUtils.isNotBlank(
                        studentQueryDTO.getPhone()),
                Student::getPhone,
                studentQueryDTO.getPhone());

        //身份证号
        queryWrapper.lambda().like(StringUtils.isNotBlank(
                        studentQueryDTO.getIdNum()),
                Student::getIdNum,
                studentQueryDTO.getIdNum());

        //申报状态
        queryWrapper.lambda().eq(studentQueryDTO.getStatus() != null,
                Student::getStatus,
                studentQueryDTO.getStatus());

        //查询指定字段
        //queryWrapper.select("id", "title");
        //排除字段查询
        queryWrapper.select(Student.class, info -> !info.getColumn().equals("deleted")
                && !info.getColumn().equals("userId"));
        //3.查询
        IPage<Student> pageResult = studentService.page(page, queryWrapper);


        //4.封装，返回
        PageVO pageVo = new PageVO<>();

        pageVo.setTotal(pageResult.getTotal());
        pageVo.setList(pageResult.getRecords());

        pageVo.setPageSize(pageResult.getSize());
        pageVo.setCurrentPage(pageResult.getCurrent());

        return SaResult.ok("查询成功").setData(pageVo);
    }



    @PostMapping("/save")
    @Operation(summary = "保存考生信息")
    public SaResult save(@RequestBody @Validated(value = { CreateGroup.class }) StudentFormDTO student){
        Student studentPo = new Student();
        BeanUtils.copyProperties(student,studentPo);
        String passwordHash = bCryptPasswordEncoder.encode(studentPo.getPassword());
        studentPo.setPassword(passwordHash);
        // 获取扩展参数
        String name = StpUtil.getExtra("name").toString();
        int userId = StpUtil.getLoginIdAsInt();
        // avatar    /uploads/images/2024/07/19/王磊/wangLei.jpg
        studentPo.setCreatedBy(name); // 创建人
        studentPo.setUserId(userId); // 创建人ID
        studentPo.setCreatedDate(LocalDateTime.now()); // 创建时间
        studentPo.setDeleted(0); // 逻辑删除标识 0表示未删除  1表示已删除
        studentPo.setStatus(0);  // 审报状态 0表示待审报  1表示已审报（当生成《职业技能等级认定个人申报审核表》更新为此状态）
        studentService.save(studentPo); // 添加考生信息
        return SaResult.ok("保存考生信息成功");
    }


    @PutMapping("/update")
    @Operation(summary = "修改考生信息")
    public SaResult update(@RequestBody @Validated(value = { UpdateGroup.class }) StudentFormDTO student){
        Student studentPo = new Student();
        BeanUtils.copyProperties(student,studentPo);
        studentService.updateById(studentPo);
        return SaResult.ok("修改考生信息成功");
    }

    @GetMapping("/detail")
    @Operation(summary = "查询考生详情")
    public SaResult detail(@RequestParam(value = "id") Integer id){
        Student student = studentService.getById(id);
        if(student == null) {
            return SaResult.error("查询失败，该考生不存在");
        }
        student.setPassword("");
        return SaResult.ok("查询成功").setData(student);
    }

    //Excel导出

     @PostMapping("/export")
     @Operation(summary = "将考生数据导出Excel",description = "根据选择考生ID集合来导出考生信息")
     public void export(@RequestBody  List<Integer> idList,HttpServletResponse response) throws Exception {
         List<StudentExcel> stuDataList = studentService.findStudentExcelByIdList(idList);
         setExcelResponseProp(response, "考生信息表.xlsx");
         EasyExcel.write(response.getOutputStream())
                 .head(StudentExcel.class)
                 .sheet()
                 .doWrite(stuDataList);
     }

    @GetMapping("/exportAll")
    @Operation(summary = "将考生数据全部导出Excel",description = "一键导出所有考生信息")
    public void exportAll(HttpServletResponse response) throws  Exception {
        List<Integer> idList  = Collections.emptyList();
        List<StudentExcel> stuDataList = studentService.findStudentExcelByIdList(idList);
        setExcelResponseProp(response, "考生信息表.xlsx"); // 下载的文件名称
        EasyExcel.write(response.getOutputStream())
                .head(StudentExcel.class)
                .sheet()  // 设置工作表的名称，默认名是：Sheet1
                .doWrite(stuDataList);
    }


    @Operation(summary = "批量Excel导入",description = "")
    @PostMapping(value = "/batchImport",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public SaResult importExcel(@RequestPart(value = "file") MultipartFile file) throws IOException  {
        if (!file.isEmpty()) {
            //文件名称
            int begin = Objects.requireNonNull(file.getOriginalFilename()).indexOf(".");
            //文件名称长度
            int last = file.getOriginalFilename().length();
            //判断文件格式是否正确
            String fileName = file.getOriginalFilename().substring(begin, last);
            if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
                throw new BizException(400,"上传文件格式错误");
            }
        } else {
            throw new BizException(400,"文件不能为空");
        }
        try (InputStream inputStream = file.getInputStream()) {
            int userId = StpUtil.getLoginIdAsInt();
            String name = String.valueOf(StpUtil.getExtra("name"));

            //获取正确数据
            ArrayList<StudentExcel> successArrayList = new ArrayList<>();

            EasyExcel.read(inputStream)
                    .head(StudentExcel.class)
                    .registerReadListener(new StudentDataListener(
                            // 监听器中doAfterAllAnalysed执行此方法；所有读取完成之后处理逻辑
                            successArrayList::addAll))
                    // 设置sheet,默认读取第一个
                    .sheet()
                    // 设置标题(字段列表)所在行数
                    .headRowNumber(1)
                    .doRead();

            List<StudentExcel> list = successArrayList.stream().map(stu -> {
                String idNo = stu.getIdNo();
                // 获取身份证号码后6位
                String password = idNo.substring(idNo.length() - 6);
                String passwordHash = bCryptPasswordEncoder.encode(password);
                stu.setCreator(name);
                stu.setPassword(passwordHash);
                stu.setUserId(userId);
                return stu;
            }).collect(Collectors.toList());

            studentService.addBatchStudents(list);
            return SaResult.ok("批量导入成功");
        } catch (IOException e) {
            throw new BizException(400,"批量导入失败");
        }

       /* InputStream is  = file.getInputStream();

        // 读取Excel文件，跳过前两行
        List<StudentExcel> stuList = EasyExcel.read(is, StudentExcel.class, new DataReaderListener())
                .headRowNumber(2) // 从第三行开始读取数据
                .sheet() // 读取第一个sheet
                .doReadSync();

        List<StudentExcel> list = stuList.stream().map(stu -> {
            String idNo = stu.getIdNo();
            // 获取身份证号码后6位
            String password = idNo.substring(idNo.length() - 6);
            String passwordHash = bCryptPasswordEncoder.encode(password);
            stu.setCreator(name);
            stu.setPassword(passwordHash);
            stu.setUserId(userId);
            return stu;
        }).collect(Collectors.toList());

        Integer rowCount = studentService.addBatchStudents(list);*/
        //return SaResult.ok("批量导入成功");
    }

    /**
     * 设置响应报文
     * @param response 响应对象
     * @param rawFileName 文件名
     * @throws UnsupportedEncodingException 不支持编码异常
     */
    private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
        /*
        "application/vnd.ms-excel"：‌这是较旧的Excel文件格式的MIME类型，‌通常用于识别早期的Excel文件格式，‌如.xls。‌
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"：‌这是用于识别较新的Excel文件格式的MIME类型，‌通常用于.xlsx文件格式。‌
         */

        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode(rawFileName, "UTF-8");
        response.setCharacterEncoding("UTF-8");
         //指定下载文件名(attachment-以下载方式保存到本地，inline-在线预览)
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
         //内容类型为通用类型，表示二进制数据流
        response.setContentType("application/octet-stream");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        //HttpServletResponse消息头参数设置
       /* response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Transfer-Encoding", "binary");
        response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
        response.setHeader("Pragma", "public");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
        String fileName = "导出文件" + ".xlsx";
        fileName = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1);
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);*/
    }



    /**
     *
     * 1、创建考生信息接口
     * 2、根据考生ID修改指定考生基本信息接口
     * 3、根据考生ID（唯一标识）逻辑删除指定考生档案信息接口
     * 4、根据考生ID获取指定考生档案信息接口
     * 5、上传考生相片接口
     * 6、重置考生密码 (以身份证号码后六位或提示输入新密码、确认新密码）提示错误消息：（密码不能为空、两次输入密码不一致)
     * 7、导入/导出学生基本信息（以Excel模板导出）
     * 8、下载指定考生照片、学历证书照片、参保证书pdf文件、身份证(人像面\国徽面)照片接口
     * 9、上传考生学历证书照片
     * 10、上传职工个人参保证明pdf文件
     * 11、上传身份证相片（人像面）
     * 12、上传身份证相片（国徽面）
     * 13、学生登录（数据隔离权限），只能查看登录学生的基本信息。
     * 14、按多条件任意组合分页查询学生基本信息列表(查询条件：姓名、身份证号、手机号、申报状态<待审报、已审报>)
     * 15*、自动认别上传身份证人像面（姓名、性别、出生年月日、地址、身份证号码、民族） —— 审报表管理的接口
     */

    @DeleteMapping("/deleted")
    @Operation(summary = "逻辑删除考生信息",description = "默认是0,1是已删除")
    public SaResult deleted(@RequestParam(value = "id") Integer id) {
        final boolean res = studentService.removeById(id);
     if (res){
        return SaResult.ok("删除成功");
    }else {
         return SaResult.error("删除失败,该考生不存在");
     }
    }
    @PostMapping("/recover")
    @Operation(summary = "恢复考生信息",description = "默认是0,1是已删除")
    public SaResult recover(@RequestParam(value = "id") Integer id) {
      studentService.recoverById(id);
        return SaResult.ok("恢复成功");
    }


    @DeleteMapping("/batchDeleted")
    @Operation(summary = "批量逻辑删除考生信息",description = "默认是0,1是已删除")
    public SaResult batchDeleted(@RequestBody List<Integer> idList) {
        List<Integer> failedIds = new ArrayList<>();
        boolean hasFailures = false;
        for (Integer id : idList) {
            final Student find = studentService.getById(id);
            // 如果学生不存在，记录ID
            if (find == null) {
                failedIds.add(id);
                hasFailures = true;
            }
        }
        // 如果没有失败情况，执行批量删除
        if (!hasFailures) {
            studentService.batchRecoverById(idList);
        }

        // 根据失败情况返回结果
        if (hasFailures) {
            String message = "批量删除部分失败，以下编号的考生不存在: " + failedIds.toString();
            return SaResult.error(message);
        } else {
            return SaResult.ok("批量删除成功");
        }
    }
    @PostMapping("/batchRecover")
    @Operation(summary = "批量恢复考生信息",description = "默认是0,1是已删除")
    public SaResult batchRecover(@RequestBody List<Integer> idList) {
        List<Integer> nonExistentIds = new ArrayList<>();
        List<Integer> List = new ArrayList<>();
        for (Integer id : idList) {
            final Student find = studentService.getById(id);
            final List<Integer> studentIds = studentService.findByIdAll();
            if (find != null && studentIds.contains(id)) {
                nonExistentIds.add(id);
            }
            if(!studentIds.contains(id)){
                List.add(id);
            }
        }

        // 如果有任何 ID 不存在，则返回错误
        if (!nonExistentIds.isEmpty()) {
            return SaResult.error("批量恢复失败，以下编号的考生已存在"+nonExistentIds);
        }
        if (!List.isEmpty()){
            return SaResult.error("批量恢复失败，以下编号的考生不存在"+List);
        }
        // 所有 ID 都不存在，执行批量恢复
        studentService.batchRecoverById(idList);

        // 返回成功
        return SaResult.ok("批量恢复成功");
    }

}